package goboot

import (
	"fmt"
	"net/http"
	"reflect"
	"runtime/debug"
	"strconv"
	"strings"
	"time"
)

// webRoute 路由处理
// 1. 初始化WebDocMethods
// 2. 绑定URL方法
// 3. 静态文件目录
// 4. 动态自动路由
func webRoute(staticFileDir *string) {

	initWebDocMethods(false)
	bindUrlMethod()

	//静态文件目录
	if staticFileDir != nil {
		fs := http.FileServer(http.Dir(*staticFileDir))
		http.Handle("/", http.StripPrefix("/", fs))
	}

	//动态自动路由

	for urlPath, webDocMethodMap := range webDocMethodUrlMap {

		finalUrlPath := urlPath

		needMatch := false
		for _, webMathod := range webDocMethodMap {

			fmt.Println("MappingUrl : " + webMathod.UrlPath + " " + webMathod.WebMethod)
			if len(webMathod.PathParams) > 0 {
				needMatch = true
				break
			}

		}

		if needMatch {
			finalUrlPath += "/*"
		}

		//fmt.Println("MappingUrl : " + finalUrlPath)

		http.HandleFunc(finalUrlPath, func(w http.ResponseWriter, r *http.Request) {
			//处理panic
			defer func() {
				if err := recover(); err != nil {

					//打印错误堆栈
					fmt.Printf("err=%v, stack=%s\n", err, string(debug.Stack()))

					serverConfig.HandleReturn(w, nil, fmt.Errorf("%v", err))
				}
			}()

			sTime := time.Now().UnixMilli()

			w.Header().Set("content-type", "application/json")
			fmt.Println("MappingUrl : " + r.Method + " " + r.URL.Path)

			//获取WebDocMethod
			webDocMethod, ok := webDocMethodMap[r.Method]
			if !ok {
				webDocMethod, ok = webDocMethodMap[""]
				if !ok {
					w.WriteHeader(http.StatusMethodNotAllowed)
					return
				}

			}

			paramMap := map[string][]any{}

			//路径参数判断
			if strings.HasSuffix(finalUrlPath, "/*") { //带路径参数

				pa := strings.Replace(r.URL.Path, finalUrlPath[:len(finalUrlPath)-2], "", 1)

				pathParams := strings.Split(pa, "/")

				if len(pathParams) != len(webDocMethod.PathParams)+1 {
					w.WriteHeader(http.StatusNotFound)
					return
				}

				//处理路径参数
				for i, pathParam := range webDocMethod.PathParams {
					paramMap[pathParam] = append(paramMap[pathParam], pathParams[i+1])
				}

			}

			if r.Method == http.MethodPost {
				r.ParseMultipartForm(10 << 20) // 10MB

				//处理POST参数
				for sss, urlParamValue := range r.PostForm {
					for _, v := range urlParamValue {
						paramMap[sss] = append(paramMap[sss], v)
					}
				}

			}
			if len(paramMap) == 0 {

				//处理参数
				r.ParseForm()

				//处理GET参数
				for sss, urlParamValue := range r.Form {
					for _, v := range urlParamValue {
						paramMap[sss] = append(paramMap[sss], v)
					}
				}

			}

			//fmt.Println(paramMap)
			selfResponseWriter := false

			var curWebUrlAspect []WebUrlAspect
			for _, aspect := range WebUrlAspectList {
				if aspect.MathchAspect(webDocMethod) {
					curWebUrlAspect = append(curWebUrlAspect, aspect)
				}
			}

			for _, aspect := range curWebUrlAspect {
				err := aspect.DoAspect(r, &paramMap)
				if err != nil {
					serverConfig.HandleReturn(w, nil, err)
					return
				}
			}

			//调用方法
			callParams := make([]reflect.Value, len(webDocMethod.ParamList))
			for i, param := range webDocMethod.ParamList {

				//处理默认值
				if param.DefStr != "" && len(paramMap[param.Name]) == 0 {
					paramMap[param.Name] = append(paramMap[param.Name], param.DefStr)
				}

				if param.TypeName == "string" {
					//必须有值
					if len(paramMap[param.Name]) == 0 {
						serverConfig.HandleReturn(w, nil, fmt.Errorf(param.Name+"参数必须有值"))
						return
					}
					var paramStr string
					if len(paramMap[param.Name]) > 0 {
						paramStr = paramMap[param.Name][0].(string)
					}
					callParams[i] = reflect.ValueOf(paramStr)
				} else if param.TypeName == "*string" {

					var paramStr *string

					if len(paramMap[param.Name]) > 0 {
						midStr := paramMap[param.Name][0].(string)
						paramStr = &midStr
					}
					callParams[i] = reflect.ValueOf(paramStr)
				} else if param.TypeName == "float64" {
					//必须有值
					if len(paramMap[param.Name]) == 0 {
						serverConfig.HandleReturn(w, nil, fmt.Errorf(param.Name+"参数必须有值"))
						return
					}

					var paramFloat64 float64
					var err error

					if len(paramMap[param.Name]) > 0 {
						paramFloat64, err = strconv.ParseFloat(paramMap[param.Name][0].(string), 64)
						if err != nil {
							panic(err)
						}
					}
					callParams[i] = reflect.ValueOf(paramFloat64)
				} else if param.TypeName == "*float64" {

					if len(paramMap[param.Name]) > 0 { //有值
						paramFloat64, err := strconv.ParseFloat(paramMap[param.Name][0].(string), 64)
						if err != nil {
							panic(err)
						}
						callParams[i] = reflect.ValueOf(&paramFloat64)
					} else {
						var paramFloat64 *float64
						callParams[i] = reflect.ValueOf(paramFloat64)
					}
				} else if param.TypeName == "*float32" {

					if len(paramMap[param.Name]) > 0 { //有值
						paramFloat32, err := strconv.ParseFloat(paramMap[param.Name][0].(string), 32)
						if err != nil {
							panic(err)
						}
						callParams[i] = reflect.ValueOf(&paramFloat32)
					} else {
						var paramFloat32 *float32
						callParams[i] = reflect.ValueOf(paramFloat32)
					}
				} else if param.TypeName == "int64" {
					//必须有值
					if len(paramMap[param.Name]) == 0 {
						serverConfig.HandleReturn(w, nil, fmt.Errorf(param.Name+"参数必须有值"))
						return
					}

					var paramInt64 int64
					var err error

					if len(paramMap[param.Name]) > 0 {
						paramInt64, err = strconv.ParseInt(paramMap[param.Name][0].(string), 10, 64)
						if err != nil {
							panic(err)
						}
					}
					callParams[i] = reflect.ValueOf(paramInt64)
				} else if param.TypeName == "*int64" {

					if len(paramMap[param.Name]) > 0 { //有值
						paramInt64, err := strconv.ParseInt(paramMap[param.Name][0].(string), 10, 64)
						if err != nil {
							panic(err)
						}
						callParams[i] = reflect.ValueOf(&paramInt64)
					} else {
						var paramInt64 *int64
						callParams[i] = reflect.ValueOf(paramInt64)
					}
				} else if param.TypeName == "int32" {
					//必须有值
					if len(paramMap[param.Name]) == 0 {
						serverConfig.HandleReturn(w, nil, fmt.Errorf(param.Name+"参数必须有值"))
						return
					}

					var paramInt32 int32

					if len(paramMap[param.Name]) > 0 {
						paramInt64, err := strconv.ParseInt(paramMap[param.Name][0].(string), 10, 32)
						if err != nil {
							panic(err)
						}
						paramInt32 = int32(paramInt64)
					}
					callParams[i] = reflect.ValueOf(paramInt32)
				} else if param.TypeName == "*int32" {

					if len(paramMap[param.Name]) > 0 { //有值
						var paramInt32 int32
						paramInt364, err := strconv.ParseInt(paramMap[param.Name][0].(string), 10, 32)
						if err != nil {
							panic(err)
						}
						paramInt32 = int32(paramInt364)
						callParams[i] = reflect.ValueOf(&paramInt32)
					} else {
						var paramInt32 *int32
						callParams[i] = reflect.ValueOf(paramInt32)
					}
				} else if param.TypeName == "int" {
					//必须有值
					if len(paramMap[param.Name]) == 0 {

						serverConfig.HandleReturn(w, nil, fmt.Errorf(param.Name+"参数必须有值"))
						return
					}

					var paramInt int
					var err error

					if len(paramMap[param.Name]) > 0 {
						paramInt, err = strconv.Atoi(paramMap[param.Name][0].(string))
						if err != nil {
							panic(err)
						}
					}
					callParams[i] = reflect.ValueOf(paramInt)
				} else if param.TypeName == "*int" {

					if len(paramMap[param.Name]) > 0 { //有值
						paramInt, err := strconv.Atoi(paramMap[param.Name][0].(string))
						if err != nil {
							panic(err)
						}
						callParams[i] = reflect.ValueOf(&paramInt)
					} else {
						var paramInt *int
						callParams[i] = reflect.ValueOf(paramInt)
					}
				} else if param.TypeName == "bool" {
					//必须有值
					if len(paramMap[param.Name]) == 0 {

						serverConfig.HandleReturn(w, nil, fmt.Errorf(param.Name+"参数必须有值"))
						return
					}

					var paramBool bool
					var err error

					if len(paramMap[param.Name]) > 0 {
						paramBool, err = strconv.ParseBool(paramMap[param.Name][0].(string))
						if err != nil {
							panic(err)
						}
					}
					callParams[i] = reflect.ValueOf(paramBool)
				} else if param.TypeName == "*bool" {

					if len(paramMap[param.Name]) > 0 { //有值
						paramBool, err := strconv.ParseBool(paramMap[param.Name][0].(string))
						if err != nil {
							panic(err)
						}
						callParams[i] = reflect.ValueOf(&paramBool)
					} else {
						var paramBool *bool
						callParams[i] = reflect.ValueOf(paramBool)
					}
				} else if param.TypeName == "http.Request" {
					panic("Request参数不能是值类型")
				} else if param.TypeName == "*http.Request" {
					callParams[i] = reflect.ValueOf(r)
				} else if param.TypeName == "http.ResponseWriter" {
					callParams[i] = reflect.ValueOf(w)
					selfResponseWriter = true
				} else {

					if len(paramMap[param.Name]) == 0 {
						callParams[i] = reflect.ValueOf(nil)

					} else {

						callParams[i] = reflect.ValueOf(paramMap[param.Name][0])
					}

				}
			}

			callReturn := webDocMethod.methodValue.Call(callParams)

			if callReturn[1].Interface() != nil { //错误
				for i := len(curWebUrlAspect) - 1; i >= 0; i-- {
					curWebUrlAspect[i].DoAspectAfter(callReturn[0].Interface(), callReturn[1].Interface().(error))
				}

			} else {
				for i := len(curWebUrlAspect) - 1; i >= 0; i-- {
					curWebUrlAspect[i].DoAspectAfter(callReturn[0].Interface(), nil)
				}
			}

			tTime := time.Now().UnixMilli()
			fmt.Printf(" %dms %s\n", tTime-sTime, r.URL.Path)

			if selfResponseWriter {
				return
			}

			if callReturn[1].Interface() != nil { //错误
				serverConfig.HandleReturn(w, callReturn[0].Interface(), callReturn[1].Interface().(error))

			} else {
				serverConfig.HandleReturn(w, callReturn[0].Interface(), nil)
			}

		})
	}

	fmt.Println("WebRoute Init Ok")

}
